import threading
from socket import socket, AF_INET, SOCK_STREAM

import wx


# 聊天室客户端的代码
class MyClientFrame(wx.Frame):

    def __init__(self, title):
        # id表示窗口编号 1001
        # title 表示窗口标题
        # pos 表示窗口位置
        # size 表示窗口大小
        super().__init__(parent=None, id=1001, title=title, pos=(100, 100), size=(400, 500))
        # 创建一个面板
        pl = wx.Panel(self)
        # 创建盒子,垂直分布
        box = wx.BoxSizer(wx.VERTICAL)

        # 创建可伸缩网格 水平布局 ,顶部开始
        grid = wx.FlexGridSizer(wx.HORIZONTAL)
        # 创建两个按钮 ，连接和断开
        self.btn_connect = wx.Button(pl, label='连接', size=(200, 40))
        self.btn_disconnect = wx.Button(pl, label='断开', size=(200, 40))
        # 把按钮添加 水平面板布局
        grid.Add(self.btn_connect, 1, wx.TOP | wx.LEFT)
        grid.Add(self.btn_disconnect, 1, wx.TOP | wx.RIGHT)
        # 把grid添加到盒子
        box.Add(grid, 1, wx.ALIGN_CENTRE)
        # 顶部结束

        # 只读文本框，显示了聊天内容
        self.text_chat = wx.TextCtrl(pl, size=(400, 210), style=wx.TE_MULTILINE | wx.TE_READONLY)
        box.Add(self.text_chat, 1, wx.ALIGN_CENTRE)

        # 输入文本框
        self.text_input = wx.TextCtrl(pl, size=(400, 120))
        box.Add(self.text_input, 1, wx.ALIGN_CENTRE)

        # 创建可伸缩网格 水平面板布局 ,底部开始
        down_grid = wx.FlexGridSizer(wx.HORIZONTAL)
        # 创建两个按钮 ，连接和断开
        self.send_btn = wx.Button(pl, label='发送', size=(200, 40))
        self.reset_btn = wx.Button(pl, label='重置', size=(200, 40))
        # 把按钮添加 水平面板布局
        down_grid.Add(self.send_btn, 1, wx.LEFT)
        down_grid.Add(self.reset_btn, 1, wx.RIGHT)
        # 把grid添加到盒子
        box.Add(down_grid, 1, wx.ALIGN_CENTRE)
        # 底部结束
        # 把盒子添加到面板
        pl.SetSizer(box)
        '''以上代码是客户端的设置，
        下面属性的设置代码'''
        self.client_name = title
        # 连接状态，默认为未连接
        self.isConnected = False
        # 客户端socket
        self.client_socket = None
        # 点击连接
        self.btn_connect.Bind(wx.EVT_BUTTON, self.click_connection_event, self.btn_connect)
        # 断开连接
        self.btn_disconnect.Bind(wx.EVT_BUTTON, self.click_disconnection_event, self.btn_disconnect)
        self.send_btn.Bind(wx.EVT_BUTTON, self.click_send_event, self.send_btn)
        self.Bind(wx.EVT_BUTTON, self.click_clear_event, self.reset_btn)

    def click_clear_event(self, event):
        self.text_input.Clear()

    # 发送消息
    def click_send_event(self, event):
        print('点击发送')
        if self.isConnected:
            # 获取输入框内容
            msg = self.text_input.GetValue()
            # 发送消息
            self.client_socket.send(msg.encode('utf-8'))
            # 清空输入框
            self.text_input.Clear()
        else:
            self.text_chat.AppendText('请先连接服务器\n')

    # 断开连接
    def click_disconnection_event(self, event):
        if self.isConnected:
            # 先服务器发送断开连接消息
            self.client_socket.send('yujikuan_disconnection'.encode('utf-8'))
            self.isConnected = False

    # 发起连接
    def click_connection_event(self, event):
        print('点击连接')
        if not self.isConnected:
            self.client_socket = socket(AF_INET, SOCK_STREAM)
            try:
                self.client_socket.connect(('127.0.0.1', 8888))
                # 发送用户名
                self.client_socket.send(self.client_name.encode('utf-8'))
                print('连接成功')
                self.text_chat.AppendText('连接成功\n')
                # self.btn_connect.Disable()
                # self.btn_disconnect.Enable()
                client_recv_thread = threading.Thread(target=self.rev_data)
                client_recv_thread.daemon = True
                self.isConnected = True
                client_recv_thread.start()
            except Exception as e:
                print('连接失败')
                self.text_chat.AppendText('连接失败\n')

    def rev_data(self):
        while self.isConnected:
            data = self.client_socket.recv(1024)
            msg = data.decode('utf-8')
            self.text_chat.AppendText("-" * 40 + "\n" + msg + "\n")
        self.client_socket.close()


if __name__ == '__main__':
    a = wx.App()
    MyClientFrame("于吉宽").Show()
    a.MainLoop()
